var ElapsedTimeBar = {
    // default value
    barColor: 'rgb(200,0,0)',
    pausedBarColor: 'rgba(200,0,0,.6)',

    isPaused: false,
    isFinished: false,

    allottedTime: null,
    timeProgressBar: null,
    startTime: null,
    pauseTime: null,
    pauseTimeDuration: 0,

    /**
     * initialize elements
     */
    handleReady() {
        var config = Reveal.getConfig();

        // activate this plugin if config.allottedTime exists.
        if (!config.allottedTime) {
            console.warn('Failed to start ElapsedTimeBar plugin. "allottedTime" property is required.');
            return;
        }

        // set configurations
        this.barColor = config.barColor || this.barColor;
        this.pausedBarColor = config.pausedBarColor || this.pausedBarColor;

        // calc barHeight from config.barHeight or page-progress container
        var barHeight;
        var pageProgressContainer = document.querySelector('.progress');
        if (config.progressBarHeight) {
            barHeight = parseInt(config.progressBarHeight, 10) + 'px';

            // override height of page-progress container
            pageProgressContainer && (pageProgressContainer.style.height = barHeight);
        } else if (config.progress && pageProgressContainer) {
            // get height from page-progress container
            barHeight = pageProgressContainer.getBoundingClientRect().height + 'px';
        } else {
            // default
            barHeight = '3px';
        }

        // create container of time-progress
        var timeProgressContainer = document.createElement('div');
        timeProgressContainer.classList.add('progress');
        Object.entries({
            display: 'block',
            position: 'fixed',
            bottom: config.progress ? barHeight : 0,
            width: '100%',
            height: barHeight
        }).forEach(([k, v]) => {
            timeProgressContainer.style[k] = v;
    });
        document.querySelector('.reveal').appendChild(timeProgressContainer);

        // create content of time-progress
        this.timeProgressBar = document.createElement('div');
        Object.entries({
            height: '100%',
            willChange: 'width'
        }).forEach(([k, v]) => {
            this.timeProgressBar.style[k] = v;
    });
        timeProgressContainer.appendChild(this.timeProgressBar);

        // start timer
        this.start(config.allottedTime);
    },

    /**
     * update repeatedly using requestAnimationFrame.
     */
    loop() {
        if (this.isPaused) return;
        var now = +new Date();
        var elapsedTime = now - this.startTime - this.pauseTimeDuration;
        if (elapsedTime > this.allottedTime) {
            this.timeProgressBar.style.width = '100%';
            this.isFinished = true;
        } else {
            this.timeProgressBar.style.width = elapsedTime / this.allottedTime * 100 + '%';
            requestAnimationFrame(this.loop.bind(this));
        }
    },

    /**
     * set color of progress bar
     */
    setBarColor() {
        if (this.isPaused) {
            this.timeProgressBar.style.backgroundColor = this.pausedBarColor;
        } else {
            this.timeProgressBar.style.backgroundColor = this.barColor;
        }
    },

    /**
     * start(reset) timer with new allotted time.
     * @param {number} allottedTime
     * @param {number} [elapsedTime=0]
     */
    start(allottedTime, elapsedTime = 0) {
        this.isFinished = false;
        this.isPaused = false;
        this.allottedTime = allottedTime;
        this.startTime = +new Date() - elapsedTime;
        this.pauseTimeDuration = 0;
        this.setBarColor();
        this.loop();
    },

    reset() {
        this.start(this.allottedTime);
    },

    pause() {
        if (this.isPaused) return;
        this.isPaused = true;
        this.pauseTime = +new Date();
        this.setBarColor();
    },

    resume() {
        if (!this.isPaused) return;

        // add paused time duration
        this.isPaused = false;
        this.pauseTimeDuration += new Date() - this.pauseTime;
        this.pauseTime = null;
        this.setBarColor();
        this.loop();
    }
};

if (Reveal.isReady()) {
    ElapsedTimeBar.handleReady();
} else {
    Reveal.addEventListener('ready', () => ElapsedTimeBar.handleReady());
}